package com.datang.litejvm.cmd;

import com.datang.litejvm.constant.ConstantPool;
import com.datang.litejvm.engin.ExecutionResult;
import com.datang.litejvm.engin.JavaObject;
import com.datang.litejvm.engin.StackFrame;

/**
 * @author 顶风少年
 * @date 2022/6/20
 */
public class ComparisonCmd extends TwoOperandCmd {

    public ComparisonCmd(ConstantPool pool, String opCode) {
        super(pool, opCode);
    }

    @Override
    public String toString() {
        return super.toString();
    }


    /**
     * @author: 顶风少年
     * @Description: int 数值的条件分支判断
     * value1 和 value2 都必须为 int 类型数据，指令执行时，value1 和 value2
     * 从操作数栈中出栈，然后进行比较运算（所有比较都是带符号的），比较的规
     * 则如下：
     *  eq 当且仅当 value1=value2 比较的结果为真。
     *  ne 当且仅当 value1≠value2 比较的结果为真。
     *  lt 当且仅当 value1<value2 比较的结果为真。
     *  le 当且仅当 value1≤value2 比较的结果为真。
     *  gt 当且仅当 value1>value2 比较的结果为真。 注意,<Java虚拟机规范（JavaSE7）.pdf>书中写错了
     *  ge 当且仅当 value1≥value2 比较的结果为真。
     * 如果比较结果为真，那无符号 byte 型数据 branchbyte1 和 branchbyte2
     * 用于构建一个 16 位有符号的分支偏移量，构建方式为（branchbyte1 << 8）
     * | branchbyte2。指令执行后，程序将会转到这个 if_icmp<cond>指令之
     * 后的，由上述偏移量确定的目标地址上继续执行。这个目标地址必须处于
     * if_icmp<cond>指令所在的方法之中。
     * 另外，如果比较结果为假，那程序将继续执行 if_acmp<cond>指令后面的其
     * 他直接码指令。
     * @date: 11:39 2022/6/20
     **/
    @Override
    public void execute(StackFrame frame, ExecutionResult result) {
        JavaObject javaObject2 = frame.getOperandStack().pop();
        JavaObject javaObject1 = frame.getOperandStack().pop();
        if (ByteCodeCommand.if_icmpne.equals(opCode)) {
            if (javaObject1.getIntValue() != javaObject2.getIntValue()) {
                gotoIndex(result);
            }
        } else if (ByteCodeCommand.if_icmple.equals(opCode)) {
            if (javaObject1.getIntValue() <= javaObject2.getIntValue()) {
                gotoIndex(result);
            }
        } else if (ByteCodeCommand.if_icmpge.equals(opCode)) {
            if (javaObject1.getIntValue() >= javaObject2.getIntValue()) {
                gotoIndex(result);
            }
        } else if (ByteCodeCommand.if_icmpgt.equals(opCode)) {
            if (javaObject1.getIntValue() > javaObject2.getIntValue()) {
                gotoIndex(result);
            }
        } else {
            throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented");
        }
    }

    public void gotoIndex(ExecutionResult result) {
        int offsetFromStartCmd = this.getOffset() + this.getIndex();
        result.setNextAction(ExecutionResult.JUMP);
        result.setNextCmdOffset(offsetFromStartCmd);
    }
}
